// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// ------------------------------------------------------------------
// Modification history:
// feature: Unified Transport Abstraction Layer Unified Transport Abstraction Layer
// feature: QoS Profile Inheritance and Composition
// feature: support msg trace log.
// feature: simplify xml profile
// ------------------------------------------------------------------

#ifndef INCLUDE_ERTPS_XMLPARSER_XMLPROFILEMANAGER_H_
#define INCLUDE_ERTPS_XMLPARSER_XMLPROFILEMANAGER_H_

#include <ertps/attributes/ParticipantAttributes.h>
#include <ertps/attributes/PublisherAttributes.h>
#include <ertps/attributes/SubscriberAttributes.h>
#include <ertps/attributes/TopicAttributes.h>
#include <xmlparser/XMLParserCommonPart.h>
#include <xmlparser/XMLProfileManagerPart.h>
#include <ertps/xmlparser/XMLParser.h>
#include <ertps/types/DynamicTypeBuilderFactory.h>
#include <ertps/types/DynamicTypeBuilder.h>

#include <xmlparser/XMLProfileManagerPart.h>

#include <string>
#include <map>
#include <mutex>

namespace evbs {
namespace ertps {
namespace xmlparser {
using vbsutil::xmlparser::XMLP_ret;
using vbsutil::xmlparser::xmlString;

using set_flags_map_t = std::map<std::string, std::vector<bool>>;

using xmlfiles_map_t = std::map<std::string, XMLP_ret>;

/**
 * Class XMLProfileManager, used to make available profiles from XML file.
 * @ingroup XMLPROFILEMANAGER_MODULE
 */
class XMLProfileManager {
    friend class XMLParser;

 public:
    /**
     * Load the default profiles XML file.
     */
    RTPS_DllAPI static void loadDefaultXMLFile();

    /**
     * Load a profiles XML file.
     * @param filename Name for the file to be loaded.
     * @param no_repeat it will parse repeated file if set to true
     * @return XMLP_ret::XML_OK if all profiles are correct, XMLP_ret::XML_NOK if some are and some
     * are not, XMLP_ret::XML_ERROR in other case.
     */
    RTPS_DllAPI static XMLP_ret loadXMLFile(const std::string& filename, bool no_repeat = true);

    /**
     * Load a profiles XML string.
     * @param data Buffer containing the data.
     * @param length Length of data.
     * @return XMLP_ret::XML_OK if all profiles are correct, XMLP_ret::XML_NOK if some are and some
     * are not, XMLP_ret::XML_ERROR in other case.
     */
    RTPS_DllAPI static XMLP_ret loadXMLString(const char* data, size_t length);

    /**
     * Load a profiles XML node.
     * @param doc Node to be loaded.
     * @return XMLP_ret::XML_OK if all profiles are correct, XMLP_ret::XML_NOK if some are and some
     * are not, XMLP_ret::XML_ERROR in other case.
     */
    RTPS_DllAPI static XMLP_ret loadXMLNode(tinyxml2::XMLDocument& doc);

    /**
     * Load a profiles XML node.
     * @param profiles Node to be loaded.
     * @return XMLP_ret::XML_OK if all profiles are correct, XMLP_ret::XML_NOK if some are and some
     * are not, XMLP_ret::XML_ERROR in other case.
     */
    RTPS_DllAPI static XMLP_ret loadXMLProfiles(tinyxml2::XMLElement& profiles);

    /**
     * Load a dynamic types XML node.
     * @param types Node to be loaded.
     * @return XMLP_ret::XML_OK on success, XMLP_ret::XML_ERROR in other case.
     */
    RTPS_DllAPI static XMLP_ret loadXMLDynamicTypes(tinyxml2::XMLElement& types);

    /**
     * Library settings setter.
     * @param library_settings New value for library settings.
     */
    RTPS_DllAPI static void library_settings(const LibrarySettingsAttributes& library_settings);

    /**
     * Library settings getter.
     * @return const ref to current library settings.
     */
    RTPS_DllAPI static const LibrarySettingsAttributes& library_settings();

    RTPS_DllAPI static XMLP_ret fillTransportAttributes(
        std::vector<std::shared_ptr<vbs::transport::TransportDescriptorInterface>>& transports,
        std::vector<std::string>& userTransports);
    /**
     * Search for the profile specified and fill the structure.
     * @param profile_name Name for the profile to be used to fill the structure.
     * @param atts Structure to be filled.
     * @param log_error Flag to log an error if the profile_name is not found.
     * @return XMLP_ret::XML_OK on success, XMLP_ret::XML_ERROR in other case. Defaults true.
     */
    RTPS_DllAPI static XMLP_ret fillParticipantAttributes(const std::string& profile_name, ParticipantAttributes& atts,
                                                          bool log_error = true);

    /**
     * Search for the profile specified and fill the structure.
     * @param profile_name Name for the profile to be used to fill the structure.
     * @param atts Structure to be filled.
     * @param log_error Flag to log an error if the profile_name is not found.
     * @return XMLP_ret::XML_OK on success, XMLP_ret::XML_ERROR in other case. Defaults true.
     */
    RTPS_DllAPI static XMLP_ret fillPublisherAttributes(const std::string& profile_name, PublisherAttributes& atts,
                                                        bool log_error = true);

    /**
     * Search for the profile specified and fill the structure.
     * @param profile_name Name for the profile to be used to fill the structure.
     * @param atts Structure to be filled.
     * @param log_error Flag to log an error if the profile_name is not found.
     * @return XMLP_ret::XML_OK on success, XMLP_ret::XML_ERROR in other case. Defaults true.
     */
    RTPS_DllAPI static XMLP_ret fillSubscriberAttributes(const std::string& profile_name, SubscriberAttributes& atts,
                                                         bool log_error = true);

    /**
     * Search for the profile specified and fill the structure.
     * @param profile_name Name for the profile to be used to fill the structure.
     * @param atts Structure to be filled.
     * @return XMLP_ret::XML_OK on success, XMLP_ret::XML_ERROR in other case.
     */
    RTPS_DllAPI static XMLP_ret fillTopicAttributes(const std::string& profile_name, TopicAttributes& atts);

    //! Fills participant_attributes with the default values.
    RTPS_DllAPI static void getDefaultParticipantAttributes(ParticipantAttributes& participant_attributes);

    //! Fills publisher_attributes with the default values.
    RTPS_DllAPI static void getDefaultPublisherAttributes(PublisherAttributes& publisher_attributes);

    //! Fills subscriber_attributes with the default values.
    RTPS_DllAPI static void getDefaultSubscriberAttributes(SubscriberAttributes& subscriber_attributes);

    //! Add a new transport instance along with its id.
    RTPS_DllAPI static bool insertTransportById(const std::string& transport_id, sp_transport_t transport);

    //! Retrieves a transport instance by its id.
    RTPS_DllAPI static sp_transport_t getTransportById(const std::string& transport_id);

    //! Fills topic_attributes with the default values.
    RTPS_DllAPI static void getDefaultTopicAttributes(TopicAttributes& topic_attributes);

    //! Add a new dynamic type instance along with its name.
    RTPS_DllAPI static bool insertDynamicTypeByName(const std::string& type_name, p_dynamictypebuilder_t type);

    //! Retrieves a transport instance by its name.
    RTPS_DllAPI static p_dynamictypebuilder_t getDynamicTypeByName(const std::string& type_name);

    /**
     * Deletes the XMLProfileManager instance.
     * EDDS's Domain calls this method automatically on its destructor, but
     * if using XMLProfileManager outside of EDDS, it should be called manually.
     */
    RTPS_DllAPI static void DeleteInstance() {
        ertps::types::DynamicTypeBuilderFactory::delete_instance();
        ;
        transport_profiles_.clear();
        dynamic_types_.clear();
        userTransportsId.clear();
        xml_files_.clear();
        vbsutil::xmlparser::XMLProfileManagerPart::DeleteInstance();
    }

    RTPS_DllAPI static XMLP_ret checkTransportId();

    static std::vector<std::string> userTransportsId;

 private:
    static xmlfiles_map_t xml_files_;

    static std::recursive_mutex mtx_xml_files_;

    static LibrarySettingsAttributes library_settings_;

    static sp_transport_map_t transport_profiles_;

    static std::mutex mtx_xml_transport_profiles_;

    static p_dynamictype_map_t dynamic_types_;

    static std::mutex mtx_xml_dynamic_types_;
};

}  // namespace xmlparser
}  // namespace ertps
} /* namespace evbs */

#endif  // INCLUDE_ERTPS_XMLPARSER_XMLPROFILEMANAGER_H_
